""": MCP Server for Crawl4AI using mcp.server (stdio) """
import asyncio
import json
from crawl4ai import AsyncWebCrawler

# MCP Server Imports
from mcp import types as mcp_types
from mcp.server.lowlevel import Server, NotificationOptions
from mcp.server.models import InitializationOptions
import mcp.server.stdio

# --- Define the Crawler Tool Schema --- 
# Define the structure of the input arguments for your tool
CRAWLER_TOOL_INPUT_SCHEMA = {
    "type": "object",
    "properties": {
        "url": {
            "type": "string",
            "description": "The URL of the web page to crawl."
        }
    },
    "required": ["url"]
}

# Define the full MCP tool schema
CRAWLER_TOOL_SCHEMA = {
    "name": "web_crawler",
    "description": "Crawls a given URL using Crawl4AI and returns the content in Markdown format.",
    "inputSchema": CRAWLER_TOOL_INPUT_SCHEMA  # Changed from parameters to inputSchema
}

# --- MCP Server Setup --- 
print("Creating MCP Server instance for Crawl4AI...")
# Create a named MCP Server instance
app = Server("crawl4ai-mcp-server")

# Implement the MCP server's @app.list_tools handler
@app.list_tools()
async def list_tools() -> list[dict]:  # Changed return type annotation
    """MCP handler to list available tools."""
    print("MCP Server: Received list_tools request.")
    print(f"MCP Server: Advertising tool: {CRAWLER_TOOL_SCHEMA['name']}")
    # Return the schema of the crawler tool we defined
    return [CRAWLER_TOOL_SCHEMA]

# Implement the MCP server's @app.call_tool handler
@app.call_tool()
async def call_tool(
    name: str, arguments: dict
) -> list[dict]:  # Changed return type annotation
    """MCP handler to execute a tool call."""
    print(f"MCP Server: Received call_tool request for '{name}' with args: {arguments}")

    # Check if the requested tool name matches our crawler tool
    if name == CRAWLER_TOOL_SCHEMA['name']:
        url = arguments.get("url")
        if not url:
            print("MCP Server: Error - 'url' argument missing.")
            error_text = json.dumps({"error": f"Missing required argument 'url' for tool '{name}'."})
            return [{"type": "text", "text": error_text}]

        print(f"MCP Server: Executing crawl for URL: {url}")
        try:
            async with AsyncWebCrawler() as crawler:
                result = await crawler.arun(url=url)

            markdown_content = "" # Default to empty string
            if result and result.markdown:
                markdown_content = result.markdown
                print(f"MCP Server: Crawling successful for {url}. Content length: {len(markdown_content)}")
            else:
                print(f"MCP Server: Crawling completed for {url} but no markdown content found.")

            # Return the result as MCP TextContent
            return [{"type": "text", "text": markdown_content}]

        except Exception as e:
            print(f"MCP Server: Error during crawling {url}: {e}")
            # Return an error message in MCP format
            error_text = json.dumps({"error": f"Failed to execute tool '{name}' for url '{url}': {str(e)}"}, indent=2)
            return [{"type": "text", "text": error_text}]
    else:
        # Handle calls to unknown tools
        print(f"MCP Server: Tool '{name}' not found.")
        error_text = json.dumps({"error": f"Tool '{name}' not implemented by this server."})
        return [{"type": "text", "text": error_text}]

# --- MCP Server Runner --- 
async def run_server():
    """Runs the MCP server over standard input/output."""
    # Use the stdio_server context manager from the MCP library
    try:
        async with mcp.server.stdio.stdio_server() as (read_stream, write_stream):
            print("MCP Server starting handshake...")
            await app.run(
                read_stream,
                write_stream,
                InitializationOptions(
                    server_name=app.name, # Use the server name defined above
                    server_version="0.1.1", # Incremented version
                    capabilities=app.get_capabilities(
                        # Define server capabilities - consult MCP docs for options
                        notification_options=NotificationOptions(),
                        experimental_capabilities={},
                    ),
                ),
            )
            print("MCP Server run loop finished.")
    except Exception as e:
        print(f"MCP Server error: {e}")
        raise

if __name__ == "__main__":
    print("Launching Crawl4AI MCP Server (stdio mode)...")
    try:
        asyncio.run(run_server())
    except KeyboardInterrupt:
        print("Crawl4AI MCP Server stopped by user.")
    except Exception as e:
        print(f"Crawl4AI MCP Server encountered an error: {e}")
    finally:
        print("Crawl4AI MCP Server process exiting.")
# --- End MCP Server --- 